#include <crt_atomic.h>

atomic_type xadd(atomic_type* ptr)
{
#if (TARGET_OS == OS_POSIX)
	__sync_add_and_fetch(ptr, 1);
	return *ptr;
#elif (TARGET_OS == OS_WINDOWS)


#if (TARGET_BITS == ARCH_64BIT)
	return InterlockedExchangeAdd64(ptr, 1);
#elif  (TARGET_BITS == ARCH_32BIT)
	return InterlockedExchangeAdd(ptr, 1);
#endif
    
#elif (TARGET_OS == OS_DARWIN)
    int32_t new_value = *ptr + 1;
    OSAtomicCompareAndSwap32Barrier(*ptr, new_value, ptr);
    return  *ptr;
#endif
	return 0;
}

atomic_type xdel(atomic_type* ptr)
{
#if (TARGET_OS == OS_POSIX)
	__sync_sub_and_fetch(ptr, 1);
	return *ptr;

#elif (TARGET_OS == OS_WINDOWS)
    
    #if (TARGET_BITS == ARCH_64BIT)
        return InterlockedExchangeAdd64(ptr, -(ssize_t)(1));
    #elif  (TARGET_BITS == ARCH_32BIT)
        return InterlockedExchangeAdd(ptr, -(ssize_t)(1));
    #endif

#elif (TARGET_OS == OS_DARWIN)
    int32_t new_value = *ptr - 1;
    OSAtomicCompareAndSwap32Barrier(*ptr, new_value, ptr);
    return *ptr;
#endif
	return 0;
}




atomic_type _atomic_init(_atomic_t *self)
{
	#if (TARGET_OS == OS_POSIX)
		__sync_lock_test_and_set(&self->value, 0);
		return self->value;
	#elif (TARGET_OS == OS_WINDOWS)

		#if (TARGET_BITS == ARCH_64BIT)
			return InterlockedExchange64(&self->value, 0);
		#elif  (TARGET_BITS == ARCH_32BIT)
			return InterlockedExchange(&self->value, 0);
		#endif

	#elif (TARGET_OS == OS_DARWIN)
    
        self->value = 0;
        OSAtomicCompareAndSwap32Barrier(self->value, 0, &self->value);
        return self->value;
	#endif

	return S_SUCCESS;
}

atomic_type _atomic_uninit(_atomic_t *self)
{
	return _atomic_init(self);
}

atomic_type _atomic_add(_atomic_t *self)
{

	#if (TARGET_OS == OS_POSIX)
		__sync_add_and_fetch(&self->value, 1);
		return self->value;
	#elif (TARGET_OS == OS_WINDOWS)

		#if (TARGET_BITS == ARCH_64BIT)
			return InterlockedExchangeAdd64(&self->value, 1);
		#elif  (TARGET_BITS == ARCH_32BIT)
			return InterlockedExchangeAdd(&self->value, 1);
		#endif
		
	#elif (TARGET_OS == OS_DARWIN)
        int32_t new_value = self->value + 1;
        OSAtomicCompareAndSwap32Barrier(self->value, new_value, &self->value);
        return self->value;
	#endif

	return S_SUCCESS;
}

atomic_type _atomic_del(_atomic_t *self)
{
	#if (TARGET_OS == OS_POSIX)
		__sync_sub_and_fetch(&self->value, 1);
		return self->value;
	#elif (TARGET_OS == OS_WINDOWS)

		#if (TARGET_BITS == ARCH_64BIT)
			return InterlockedExchangeAdd64(&self->value, -(ssize_t)(1));
		#elif  (TARGET_BITS == ARCH_32BIT)
			return InterlockedExchangeAdd(&self->value, -(ssize_t)(1));
		#endif

	#elif (TARGET_OS == OS_DARWIN)
        int32_t new_value = self->value - 1;
        OSAtomicCompareAndSwap32Barrier(self->value, new_value, &self->value);
        return self->value;
	#endif

	return S_SUCCESS;
}

void _atomic_set(_atomic_t *self, void *value)
{
#if (TARGET_OS == OS_WINDOWS)
	InterlockedExchangePointer((volatile PVOID*) &self->value, value);
#elif (TARGET_OS == OS_POSIX)
	#if defined(__GNUC__) && (__GNUC__ >= 4)
		(void) __sync_lock_test_and_set(&self->value, value);
	#else
		(void) self;
		(void) value;
	#endif

#elif (TARGET_OS == OS_DARWIN)
	(void) self;
	(void) value;
#endif
}

atomic_type _atomic_cas(_atomic_t *self, atomic_type oldval, atomic_type newval)
{
#if (TARGET_OS == OS_WINDOWS) 
	return _InterlockedCompareExchange(&self->value, oldval, newval);
#elif (TARGET_OS == OS_POSIX) 
	
	#if defined(__GNUC__) && (__GNUC__ >= 4)
		return __sync_bool_compare_and_swap(&self->value, oldval, newval);
	#else 
		(void) self;
		(void) oldval;
		(void) newval;
		return oldval;
	#endif 

#elif (TARGET_OS == OS_DARWIN)
	(void) self;
	(void) oldval;
	(void) newval;
	return oldval;
#endif

}

void _atomic_xchg(_atomic_t *self, void *value)
{
#if (TARGET_OS == OS_WINDOWS)
     InterlockedExchangePointer((volatile PVOID*)&self->value, value);
#elif  (TARGET_OS == OS_POSIX) 

	#if defined(__GNUC__) && (__GNUC__ >= 4)
		__sync_lock_test_and_set(&self->value, value);
	#else
		(void) self;
		(void) value;
	#endif

#elif  (TARGET_OS == OS_DARWIN)
	
	(void) self;
	(void) value;
#endif
 }









